﻿/*+===================================================================
File:      EnemySniper.cpp

Summary:   Định nghĩa các phương thức của CEnemySniper.
===================================================================+*/

#include "EnemySniper.h"
#include "PlayState.h"
#include "Explosion.h"

// Các trạng thái của EnemySniper.
#define STATUS_STAND		0
#define STATUS_TOP			1
#define STATUS_BOT			2
#define STATUS_DIE          3

#define MAX_BULLETS         3

CEnemySniper::CEnemySniper(CBill* bill, D3DXVECTOR2 pos, int id, int typeId) : CMoveableObject(pos, id, typeId)
{
	CResourcesManager::GetInstance()->GetSprite(ID_SPRITE_ENEMY_SNIPER_STAND);
	CResourcesManager::GetInstance()->GetSprite(ID_SPRITE_ENEMY_SNIPER_STAND_FIRE);
	CResourcesManager::GetInstance()->GetSprite(ID_SPRITE_ENEMY_SNIPER_TOP);
	CResourcesManager::GetInstance()->GetSprite(ID_SPRITE_ENEMY_SNIPER_TOP_FIRE);
	CResourcesManager::GetInstance()->GetSprite(ID_SPRITE_ENEMY_SNIPER_BOT);
	CResourcesManager::GetInstance()->GetSprite(ID_SPRITE_ENEMY_SNIPER_BOT_FIRE);
	m_bill = bill;
	m_nStatus = STATUS_STAND;
	m_pSprite = m_pResourceManager->GetSprite(ID_SPRITE_ENEMY_SNIPER_STAND);
	m_bIsRight = false;
	m_bIsFiring = false;
	m_pGun = new CGun(ID_ENEMY_SMALL_WHITE_BULLET, MAX_BULLETS, 1);
	m_box.width = 48;
	m_box.height = 78;
	m_v.y = 200.0f;
}

CEnemySniper::~CEnemySniper()
{
	if (m_pGun)
		delete m_pGun;
	if (m_bill)
		delete m_bill;
}

void CEnemySniper::UpdateAnimation()
{
	if (!m_bIsFiring)
	{
		switch (m_nStatus)
		{
			case STATUS_STAND:
				m_pSprite = m_pResourceManager->GetSprite(ID_SPRITE_ENEMY_SNIPER_STAND);
				break;
			case STATUS_TOP:
				m_pSprite = m_pResourceManager->GetSprite(ID_SPRITE_ENEMY_SNIPER_TOP);
				break;
			case STATUS_BOT:
				m_pSprite = m_pResourceManager->GetSprite(ID_SPRITE_ENEMY_SNIPER_BOT);
				break;
			case STATUS_DIE:
				m_pSprite = m_pResourceManager->GetSprite(ID_SPRITE_ENEMY_SNIPER_TOP);
				break;
		}
	}
	else
	{
		switch (m_nStatus)
		{
			case STATUS_STAND:
				m_pSprite = m_pResourceManager->GetSprite(ID_SPRITE_ENEMY_SNIPER_STAND_FIRE);
				break;
			case STATUS_TOP:
				m_pSprite = m_pResourceManager->GetSprite(ID_SPRITE_ENEMY_SNIPER_TOP_FIRE);
				break;
			case STATUS_BOT:
				m_pSprite = m_pResourceManager->GetSprite(ID_SPRITE_ENEMY_SNIPER_BOT_FIRE);
				break;
			case STATUS_DIE:
				m_pSprite = m_pResourceManager->GetSprite(ID_SPRITE_ENEMY_SNIPER_TOP);
				break;
		}
	}
}

void CEnemySniper::Update(float timeFrame)
{
	if (!m_bIsLive)
	{
		// Tính toán hiệu ứng khi enemy bị trúng đạn, Enemy
		// sẽ bị nảy lên đến một thời gian nào đó và nổ.
		if (m_timeDie > 0)
		{
			m_timeDie -= timeFrame;
			m_pos.y += m_v.y * timeFrame;
		}
		else if (m_timeDie < 0)
		{
			m_timeDie = 0.0f;
			Kill();
		}

		UpdateAnimation();
		return;
	}

	// Cập nhật thời gian bắn giữ 2 viên đạn.
	if (m_bIsFiring)
	{
		if (m_fTimeFire > 0)
			m_fTimeFire -= timeFrame;
		else
		{
			m_fTimeFire = 0.0f;
			m_bIsFiring = false;
		}
	}

	// Cập nhật thời gian bắn giữ loạt 3 viên đạn.
	if (m_fTimeReFire > 0)
		m_fTimeReFire -= timeFrame;
	else 
	{
		// Khi thời gian hết thời gian chờ lượt bắn ta mới cho EnemySniper
		// cập nhật trạng thái và góc bắn theo Bill.
		m_fTimeReFire = 0.0f;
		if (m_nBulletsFired == MAX_BULLETS)
			m_nBulletsFired = 0;

		D3DXVECTOR2 billPos = m_bill->GetPos();

		// Tính toán góc của bill so với vị trí của EnemySniper.
		// Dời tọa độ gốc(0, 0) về tọa độ của EnemySniper để tính góc.
		float angle = atan2(billPos.y - m_pos.y, billPos.x - m_pos.x) * 180 / PI;

		// Các góc chuyển Sprite.
		if (angle > 0 && 7.5 < angle && angle  < 180 - 7.5)
		{
			m_nStatus = STATUS_TOP;
		}
		else if (angle < 0 && -7.5 > angle && angle > -180 + 7.5)
		{
			m_nStatus = STATUS_BOT;
		}
		else
		{
			m_nStatus = STATUS_STAND;
		}

		if (-90 < angle && angle < 90)
			m_bIsRight = true;
		else
			m_bIsRight = false;

		// Công thức ảo diệu tính đc góc bắn.
		int temp = angle / 7.5;
		temp = (temp / 2) + temp % 2;
		angle = temp * 180 / 12;

		m_pGun->SetBulletAngle(angle);
	}
	
	// Cập nhật việc bắn đạn.
	if (!m_bIsFiring && m_nBulletsFired < MAX_BULLETS)
	{
		// Tính toán vị trí của đạn bắn ra.
		switch (m_nStatus)
		{
			case STATUS_STAND:
				m_bulletPos.x = m_pos.x - m_pSprite->GetWidth() / 2.0f;
				m_bulletPos.y = m_pos.y + m_pSprite->GetHeight() / 2.0f - 20;
				break;
			case STATUS_TOP:
				m_bulletPos.x = m_pos.x - m_pSprite->GetWidth() / 2.0f;
				m_bulletPos.y = m_pos.y + m_pSprite->GetHeight() / 2.0f;
				break;
			case STATUS_BOT:
				m_bulletPos.x = m_pos.x - m_pSprite->GetWidth() / 2.0f - 2;
				m_bulletPos.y = m_pos.y - 16;
				break;
		}
		
		if (m_bIsRight)
			m_bulletPos.x = m_pos.x + (m_pos.x - m_bulletPos.x);

		m_bIsFiring = m_pGun->Fire(m_bulletPos);
		if (m_bIsFiring)
		{
			m_nBulletsFired++;
			m_fTimeFire = 0.4f;

			// Khi đã bắn hết đạn trong lượt đó.
			if (m_nBulletsFired == MAX_BULLETS)
				m_fTimeReFire = 3.0f;
		}
	}
	
	m_pSprite->Update(timeFrame);
	UpdateAnimation();
	UpdateBox(timeFrame);
}

void CEnemySniper::UpdateCollision(vector<CGameObject*> vecGameObjs, float timeFrame)
{
	
	if (!m_bIsLive)
		return;

	float timeCollision = timeFrame;
	CGameObject* objCollision = NULL; // Đối tượng va chạm sớm nhất.
	float normalx = 0.0f, normaly = 0.0f;

	// Xử lí va chạm với đạn của Bill
	for (int i = 0; i < CPlayState::s_billBullets.size(); i++)
	{
		if (CPlayState::s_billBullets[i]->IsLive())
		{
			float t = CheckCollision(CPlayState::s_billBullets[i], normalx, normaly, timeFrame);

			if (t < timeFrame && t < timeCollision)
			{
				// Tìm đối tượng và thời gian va chạm sớm nhất.
				timeCollision = t;
				objCollision = CPlayState::s_billBullets[i];
			}
		}
	}

	// Xử lí va chạm
	if (objCollision != NULL)
	{
		m_timeDie = 0.18f;
		m_nStatus = STATUS_DIE;
		m_bIsLive = false;
		objCollision->Kill();
	}
}

void CEnemySniper::Draw()
{
	if (!m_bIsLive && m_timeDie == 0.0f)
		return;
	D3DXVECTOR2 pos = CViewport::GetInstance()->TransformMatrix(m_pos);
	if (!m_bIsRight)
		m_pSprite->Draw(pos);
	else
		m_pSprite->DrawFlipX(pos);

}

bool CEnemySniper::Kill()
{
	CExplosion* explosion = new CExplosion(m_pos, 0, ID_ENEMY_EXPLOSION);
	CPlayState::s_objsOutSideQuadTree.push_back(explosion);
	g_nScore += 100;
	return true;
}